module AXI_Lite_Sel(
  input ACLK ,
  input ARESETn,
  
  //AXI-Lite Slave interface 0
  input [63:0] AWADDR,
  input [2:0] AWPROT,
  input AWVALID,
  input [63:0] WDATA,
  input [7:0] WSTRB,
  input WVALID,
  input BREADY,
  input [63:0] ARADDR,
  input [2:0] ARPROT,
  input ARVALID,
  input RREADY,
  output reg AWREADY,
  output reg WREADY,
  output reg [1:0] BRESP,
  output reg BVALID,
  output reg ARREADY,
  output reg [63:0] RDATA,
  output reg [1:0] RRESP,
  output reg RVALID,

  //AXI-Lite Master interface 0
  output reg [63:0] AWADDR_0,
  output reg [2:0] AWPROT_0,
  output reg AWVALID_0,
  output reg [63:0] WDATA_0,
  output reg [7:0] WSTRB_0,
  output reg WVALID_0,
  output reg BREADY_0,
  output reg [63:0] ARADDR_0,
  output reg [2:0] ARPROT_0,
  output reg ARVALID_0,
  output reg RREADY_0,
  input AWREADY_0,
  input WREADY_0,
  input [1:0] BRESP_0,
  input BVALID_0,
  input ARREADY_0,
  input [63:0] RDATA_0,
  input [1:0] RRESP_0,
  input RVALID_0,

  //AXI-Lite Master interface 1
  output reg [63:0] AWADDR_1,
  output reg [2:0] AWPROT_1,
  output reg AWVALID_1,
  output reg [63:0] WDATA_1,
  output reg [7:0] WSTRB_1,
  output reg WVALID_1,
  output reg BREADY_1,
  output reg [63:0] ARADDR_1,
  output reg [2:0] ARPROT_1,
  output reg ARVALID_1,
  output reg RREADY_1,
  input AWREADY_1,
  input WREADY_1,
  input [1:0] BRESP_1,
  input BVALID_1,
  input ARREADY_1,
  input [63:0] RDATA_1,
  input [1:0] RRESP_1,
  input RVALID_1 

);
  wire clk = ACLK;
  wire rst = ~ARESETn;
  
  localparam FSM_SEL0 = 1'b0;
  localparam FSM_SEL1 = 1'b1;
  localparam SEL1_ADDR = 36'h0;
  reg [0:0] cstate,nstate;
  
  wire [35:0] request_addr = {36{AWVALID}}&AWADDR[63:28]|{36{ARVALID}}&ARADDR[63:28];
  wire trans_end_0 = (RVALID_0&RREADY_0) | (BVALID_0&BREADY_0);
  wire trans_end_1 = (RVALID_1&RREADY_1) | (BVALID_1&BREADY_1);
  wire trans_request = (AWVALID|ARVALID);

  reg idle;
  always @(posedge clk) begin
    if(rst) begin
      cstate <= FSM_SEL0;
    end else begin
      cstate <= nstate;
    end
  end

  always @(*) begin
    nstate = cstate;
    if(trans_request&idle)
      case(request_addr)
      SEL1_ADDR: nstate = FSM_SEL1;
      default: nstate = FSM_SEL0;
      endcase
  end

  always @(posedge clk) begin
    if(rst) begin
      idle <= 1'b1;
    end else begin
      if(trans_request&idle) idle <= 1'b0;
      if(trans_end_0|trans_end_1) idle <= 1'b1;
    end
  end

  localparam BUS_WIDTH_O = 64+3+1+64+8+1+1+64+3+1+1;
  localparam BUS_WIDTH_I = 1+1+2+1+1+64+2+1;
  wire [BUS_WIDTH_O-1:0] slave;
  wire [BUS_WIDTH_I-1:0] master_0,master_1;
  assign slave = {AWADDR,AWPROT,AWVALID,WDATA,WSTRB,WVALID,BREADY,ARADDR,ARPROT,ARVALID,RREADY};
  assign master_0 = {AWREADY_0,WREADY_0,BRESP_0,BVALID_0,ARREADY_0,RDATA_0,RRESP_0,RVALID_0};
  assign master_1 = {AWREADY_1,WREADY_1,BRESP_1,BVALID_1,ARREADY_1,RDATA_1,RRESP_1,RVALID_1};
  always @(*) begin
    {AWREADY,WREADY,BRESP,BVALID,ARREADY,RDATA,RRESP,RVALID} ={BUS_WIDTH_I{1'b0}};
    {AWADDR_0,AWPROT_0,AWVALID_0,WDATA_0,WSTRB_0,WVALID_0,BREADY_0,ARADDR_0,ARPROT_0,ARVALID_0,RREADY_0} = {BUS_WIDTH_O{1'b0}};
    {AWADDR_1,AWPROT_1,AWVALID_1,WDATA_1,WSTRB_1,WVALID_1,BREADY_1,ARADDR_1,ARPROT_1,ARVALID_1,RREADY_1} = {BUS_WIDTH_O{1'b0}};
    if(cstate == nstate)
    case(cstate)
    FSM_SEL0: begin
      {AWREADY,WREADY,BRESP,BVALID,ARREADY,RDATA,RRESP,RVALID} = master_0;
      {AWADDR_0,AWPROT_0,AWVALID_0,WDATA_0,WSTRB_0,WVALID_0,BREADY_0,ARADDR_0,ARPROT_0,ARVALID_0,RREADY_0} = slave;
      {AWADDR_1,AWPROT_1,AWVALID_1,WDATA_1,WSTRB_1,WVALID_1,BREADY_1,ARADDR_1,ARPROT_1,ARVALID_1,RREADY_1} = {BUS_WIDTH_O{1'b0}};
    end
    FSM_SEL1: begin
      {AWREADY,WREADY,BRESP,BVALID,ARREADY,RDATA,RRESP,RVALID} = master_1;
      {AWADDR_0,AWPROT_0,AWVALID_0,WDATA_0,WSTRB_0,WVALID_0,BREADY_0,ARADDR_0,ARPROT_0,ARVALID_0,RREADY_0} = {BUS_WIDTH_O{1'b0}};
      {AWADDR_1,AWPROT_1,AWVALID_1,WDATA_1,WSTRB_1,WVALID_1,BREADY_1,ARADDR_1,ARPROT_1,ARVALID_1,RREADY_1} = slave;
    end
    default:  begin
      {AWREADY,WREADY,BRESP,BVALID,ARREADY,RDATA,RRESP,RVALID} ={BUS_WIDTH_I{1'b0}};
      {AWADDR_0,AWPROT_0,AWVALID_0,WDATA_0,WSTRB_0,WVALID_0,BREADY_0,ARADDR_0,ARPROT_0,ARVALID_0,RREADY_0} = {BUS_WIDTH_O{1'b0}};
      {AWADDR_1,AWPROT_1,AWVALID_1,WDATA_1,WSTRB_1,WVALID_1,BREADY_1,ARADDR_1,ARPROT_1,ARVALID_1,RREADY_1} = {BUS_WIDTH_O{1'b0}};
    end
    endcase
  end
endmodule
